
import java.util.LinkedList;
import java.util.Random;

import processing.core.PApplet;
import processing.core.PMatrix3D;


public class TubeHallitsija {
	private boolean oikealle, vasemmalle, ylos, alas, suoraan = false;
	private float suuntaX;
	private float suuntaY;
	private int kameraZ;
	private int suoraLaskuri;
	private int paloja;
	private int pts; // poikkileikkauksen kulmien lkm.
	private int speed;
	private float aloitusaika;
	private int aika;
	private float vaikeus;
	private PMatrix3D siirto;
	private Tuberunner p; // emäntä-PAppletin kautta tehdään processing-käskyt
	private LinkedList<Poikkileikkaus> poikkileikkaukset; // säilöö linkit poikkileikkauksista
	static Random rand = new Random();

	public TubeHallitsija(Tuberunner father, int kameraZ)
	{
		this.speed = 0;
		this.paloja = 40;
		this.pts = 30;
		this.p = father;
		this.kameraZ = kameraZ;
		this.poikkileikkaukset = new LinkedList<Poikkileikkaus>();
		this.alustaTube();
		this.siirto = new PMatrix3D();
		this.siirto.translate(0, 0, 100);
		this.aloitusaika = p.millis();
		this.aika= 0;
		this.vaikeus = 0;
	}

	public LinkedList<Poikkileikkaus> getPl()
	{
		return this.poikkileikkaukset;
	}
	public int getSpeed()
	{
		return this.speed;
	}

	public int getAika()
	{
		return this.aika;
	}
	/**
	 * Tällä metodilla siirretään tuubin jokaista poikkileikkausta eli koko tuubia pykälä lähemmäksi kameraa.
	 * 
	 * @author chriisu
	 * @param Zspeed on z-akselin muutos
	 */
	public void liikuTuubi(int Zspeed) {
		this.speed = Zspeed+(int)vaikeus;
		//		System.out.println(speed);
		// K�yd��n poikkileikkaukset l�pi iteraattorilla
		//Iterator<Poikkileikkaus> i = this.poikkileikkaukset.iterator();
		poikkileikkaukset.getFirst().liikuta(speed); //ekan palan siirt�minen liikuttaa nyt koko putkea

		// Kun tuubin z on tarpeeksi l�hell� kameran arvoa, se poistetaan
		for (int a = 0; a < this.paloja; a++) { 
			if (poikkileikkaukset.get(a).dz < this.kameraZ) {
				this.poikkileikkaukset.remove(a);
				this.lisaaPoikkileikkaus();
			}
		}
		this.aika = (int)(p.millis() - aloitusaika)/1000;
		this.vaikeus = aika/5;
	}
	
	// metodi generoi tuubin tulevaisuutta.
	public void generoi()
	{
		if(suoraan)
		{
			suoraLaskuri ++;
			if(suoraLaskuri > 80)
			{
				suoraLaskuri = 0;
				suoraan = false;
			}
		}
		else
		{
			if(oikealle)
			{
				suuntaX += 0.0005;
				if(suuntaX > 0.02)
					oikealle = false;
			}
			if(vasemmalle)
			{
				suuntaX -= 0.0005;
				if(suuntaX < -0.02)
					vasemmalle = false;
			}
			if(ylos)
			{
				suuntaY += 0.0005;
				if(suuntaY > 0.02)
					ylos = false;
			}
			if(alas)
			{
				suuntaY -= 0.0005;
				if(suuntaY < -0.02)
					alas = false;
			}
		}
		//		if(kasvu)
		//		{
		//			suuntaX += 0.001;//suunta kaantaa putkea x suunnassa
		//			suuntaY += 0.001;
		//		}
		//		else{
		//			suuntaX -= 0.001;
		//			suuntaY -= 0.001;
		//		}
		//		if(suuntaX < -0.05 || suuntaX > 0.05)
		//		{
		//			kasvu = !kasvu; //putki eessun taassun sivulta sivulle t�n avulla
		//		}
		if(!oikealle && !vasemmalle && !ylos && !alas)
		{
			//suuntaX = suuntaY = 0;
			int arpa = rand.nextInt(3);
			int arpa2 = rand.nextInt(2);
			if(arpa == 0)
			{
				suoraan = true;
				suuntaX = suuntaY = 0;
			}
			else
			{
				if(arpa == 1)
				{
					oikealle = true;
				}
				else if(arpa == 2)
				{
					vasemmalle = true;
				}
				if(arpa2 == 0)
				{
					ylos = true;
				}
				else
				{
					alas = true;
				}
			}
		}
	}


	// lisaa poikkileikkauksen ja saattaa asettaa siihen Esineen.
	private void lisaaPoikkileikkaus() {
		generoi();
		Poikkileikkaus pl = new Poikkileikkaus(0, 0, 0, suuntaX, suuntaY, this.pts, this.p);
		this.poikkileikkaukset.add(pl);

		pl.asetaEsine(this.generoiEsine()); // asetetaan poikkileikkaukseen esine
	}
	//alustaa tuubin alkupatkan
	public void alustaTube()
	{
		for (int a = 0; a < this.paloja; a++)
		{
			Poikkileikkaus pl = new Poikkileikkaus(0, 0, 0, 0, 0, this.pts, this.p);
			this.poikkileikkaukset.add(pl);
		}
	}
	//piirtaa putken
	public void piirto()
	{
		for(int i = 1; i<poikkileikkaukset.size(); i++)
		{
			//otetaan kaksi lapileikkausta kerrallaan kasittelyyn ja piirretaan niiden valille quadstrip
			Poikkileikkaus prev = poikkileikkaukset.get(i-1);
			Poikkileikkaus now = poikkileikkaukset.get(i);

			//lasketaan kohta johon poikkileikkaus now asetetaan
			for(int a = 0; a < i; a++)
			{

				now.kerroMatriisilla(poikkileikkaukset.get(a).getMat());
			}

			p.beginShape(PApplet.QUAD_STRIP);
			for (int j = 0; j <= pts; j++)
			{
				p.vertex(prev.getX(j), prev.getY(j), prev.getZ(j));
				p.vertex(now.getX(j), now.getY(j), now.getZ(j));
			}
			p.endShape();

			//chriisu extra! objektin piirto
			Esine e = now.annaEsine();
			if (e != null) {
				p.pushMatrix();
				int j = e.givePositio();
				p.translate(now.getX(j), now.getY(j)-50, now.getZ(j));
				//				System.out.println("x" + now.x + " y" + now.y + " z" + now.z);
				e.piirra();
				p.popMatrix();
			}
			//			System.out.print(now.y);
			//			if (i == poikkileikkaukset.size()-2) {
			//				System.out.println();
			//			}
		}
		//alustetaan jokainen poikkileikkaus
		for(int i = 0; i<poikkileikkaukset.size(); i++)
		{
			poikkileikkaukset.get(i).reset();
		}


	}

	// Generoi tietylla todennakoisyydella IceCuben, muutoin palauttaa null
	/*
	 * Alunperin tarkoituksena oli luoda myos muita esineita peliin, mutta aikarajan lahestyessa loyhasimme
	 * spekseja ja tyydyimme pelkkaan jaakuutioon, koska muita objekteja oli vaikea kaantaa nakymaan oikein
	 * ja jaakuutio sopi paremmin pelin teemaan.
	 */
	public Esine generoiEsine() {
		Esine esine;
		int esineVaikeus = (int) vaikeus/5;
		//		System.out.println("esineet "+ esineVaikeus);
		
		if(aika>100)//satkussa tube alkaa kiitaa niin kovaa etta otetaan esteita vaha pois
		{
			esineVaikeus = (int) (vaikeus-20)/5;
		}
		if(esineVaikeus > 5)
		{
			esineVaikeus = 5;
		}
		int arpa = rand.nextInt(8-esineVaikeus);
		if (arpa == 0) { // IceCube
			esine = new IceCube(this.p, this.pts);
		}
		//		else if (arpa == 1) { // Lappari
		//			esine = new Lappari(this.p, this.pts);
		//			//			esine = null;
		//		}
		//		else if (arpa == 3){ // Pullo
		//			esine = new Pullo(this.p, this.pts);
		//			esine = null;
		//			//System.out.println("Pulla luotu!");
		//		}
		else { 
			esine = null;
		}
		return esine;
	}

}
